package org.example.ReferenceType;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

/**
 * 虚引用（PhantomReference）：
 * 虚引用是一种特殊的引用类型，它与软引用和弱引用不同，它不会决定对象的生命周期，也不会影响对象的回收。
 * 虚引用主要用来跟踪对象被垃圾回收器回收了，但finalize()方法还没有被调用的对象。虚引用与软引用和弱引用的区别在于：
 * 软引用：当内存不足时，软引用对象会被回收，但是只要系统内存足够，软引用对象不会被回收。
 * 弱引用：弱引用对象只能存活到下一次垃圾回收之前，当垃圾回收发生时，弱引用对象会被回收。
 * 虚引用：虚引用对象也不能决定对象的生命周期，它唯一能做的就是通知被引用的对象，在finalize()方法被调用前，它会一直存在。
 * 虚引用的主要作用是跟踪对象被垃圾回收器回收了，但finalize()方法还没有被调用的对象。
 * 虚引用的使用场景：
 * 1. 缓存技术：虚引用可以用来缓存对象，当缓存的对象被回收时，虚引用可以通知缓存系统删除缓存对象。
 * 2. 监听器：虚引用可以用来监听对象的回收情况，当对象被回收时，虚引用可以通知监听器做一些后续操作。
 * 3. 资源释放：虚引用可以用来释放资源，当对象被回收时，虚引用可以调用资源释放方法，比如关闭数据库连接、释放文件句柄等。
 * 4. 线程终止：虚引用可以用来终止线程，当线程终止时，虚引用可以通知线程终止。
 * 5. 其他：虚引用可以用来做一些其他的事情，比如跟踪对象的垃圾回收情况，统计对象的被引用次数等。
 * 总结：虚引用是一种特殊的引用类型，它与软引用和弱引用不同，它不会决定对象的生命周期，也不会影响对象的回收。
 * 虚引用主要用来跟踪对象被垃圾回收器回收了，但finalize()方法还没有被调用的对象。
 */
public class T03_PhantomReference {
    private static final List<Object> LIST = new LinkedList<>();
    private static final ReferenceQueue<M> QUEUE =  new ReferenceQueue<>();

    public static void main(String[] args) {
        PhantomReference<M> phantomReference = new PhantomReference<>(new M(), QUEUE);

        new Thread(() -> {
           while(true) {
               LIST.add(new byte[1024*1024]);
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
                   Thread.currentThread().interrupt() ;
               }
               System.out.println(phantomReference.get());
           }
        }).start();
        new Thread(() -> {
            while (true) {
                    Reference<? extends M> poll = QUEUE.poll();
                    if(poll != null) {
                        System.out.println("-----虚引用被Java对象回收了---" + poll);
                    }
            }
        }).start();

        try {
            Thread.sleep(1000);

        }catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}
